home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
pctj8505.arc
/
MARQFIT.BAS
< prev
next >
Wrap
BASIC Source File
|
1986-09-14
|
34KB
|
669 lines
1 ' PROGRAM MARQFIT.BAS -- a non-linear least squares fitting
2 ' routine using the marquardt algorithm
5 ' (c) 1985 W. Schreiner, M. Kramer, S. Krischer, & Y. Langsam
20 '-------------- initialize program settings ---------------
30 REV = 2.1 : PI = 3.14159265#
40 ON ERROR GOTO 19000 : RETCOD = 0 :KEY OFF
60 DEF SEG=64:POKE 23,(PEEK(23) OR 64): DEF SEG 'set caps lock
65 ' The values MXVAR%, MXOBS% and MDI% can be changed-
70 ' be sure to change the DIM sizes correspondingly
80 MXVAR% = 30:MXOBS% = 500 : MDI% = MXVAR% * (MXVAR% + 1) / 2
90 DIM X(500),DTA(500),WGT(500),FXP(500),FYP(500),XP(500)
100 DIM YP(500),C(465),A(465),B(30),DPARM(30),PARM(30), KFIX(30),DERIV(30),G(30),GRAD(30)
110 DEF FNLGT(X) = LOG(X)/LOG(10)
120 ON KEY(1) GOSUB 10200 : ON KEY(2) GOSUB 10300
130 ON KEY(3) GOSUB 10310 : ON KEY(4) GOSUB 10400
140 KEY(1) ON : KEY(2) ON : KEY(3) ON : KEY(4) ON
160 FG=2:BG=0:FG1=14:BG1=0:FG2=4:BG2=0 ' color attributes
165 FOR I = 1 TO MXOBS% : WGT(I) = 1 : NEXT
190 ' ---------------plot routine initialization
200 PLOTSET% = 0 ' plot definition flag
210 XTOTAL.PIX = 639: YTOTAL.PIX = 199
220 ' (for lo_res use XTOTAL.PIX = 319)
230 ' XMIN.PIX is lower left hand xmin in pixel coords;
240 ' YMIN.PIX is lower left hand ymin in pixel coords;
250 ' XMIN and YMIN are the same but in USER coordinates
260 XMIN.PIX=CINT(.11*XTOTAL.PIX): XMAX.PIX=.94*XTOTAL.PIX
270 YMAX.PIX=CINT(.07*YTOTAL.PIX)-2: YMIN.PIX=YTOTAL.PIX-12
280 DELTAX.PIX = XMAX.PIX-XMIN.PIX+1
290 DELTAY.PIX = YMIN.PIX-YMAX.PIX+1
310 ' functions to convert X & Y in user coords --> pixel coords
320 DEF FNSX(N)=XMIN.PIX + CINT((N-XMIN)*DELTAX.PIX/(XMAX-XMIN))
330 DEF FNSY(N)=YMIN.PIX - CINT((N-YMIN)*DELTAY.PIX/(YMAX-YMIN))
335 ' ------------------------start up--------------------------
340 IPFLG = 0 ' pause-in-fitting flag
350 ISVFL = - 1 ' data saved flag
360 CLS : LOCATE 10 : COLOR FG2,BG2 : PRINT TAB(15) "MARQUARDT LEAST SQUARES - REV ";REV:
365 COLOR FG,BG : FOR I = 1 TO 1700: NEXT:LOCATE 20
370 INPUT "USE DATA ON DRIVE (ENTER LETTER):";DRV$: DRV$ =LEFT$(DRV$,1) : IF DRV$ <> "" THEN DRV$=DRV$+":"
380 GOTO 420
390 ' ----------------------- menu --------------------------
400 PRINT "PRESS ANY KEY TO CONTINUE":WHILE INKEY$ = "":WEND
410 RETCOD = 0 ' reset error flag
420 F1%=0:SCREEN 0 :CLS: GOSUB 10000: COLOR FG2,BG: LOCATE 1,20
425 PRINT "MENU OPTIONS:": COLOR FG,BG : PRINT:COLOR FG1,BG1
430 PRINT TAB(6) "GENERAL:";:COLOR FG,BG
435 PRINT TAB(21) "1- ENTER TITLE " 'line 800
440 PRINT TAB(21) "2- PRINTER "; 'line 850
450 IF PFLG% = 0 THEN PRINT "ON/";:COLOR FG1,BG1:PRINT "OFF": COLOR FG,BG ELSE COLOR FG1,BG1: PRINT "ON";: COLOR FG,BG : PRINT "/OFF"
460 PRINT TAB(21) "3- SOLVE " 'line 900
470 PRINT TAB(21) "4- PLOT " 'line 15000
480 PRINT TAB(21) "5- QUIT " 'line 1300
490 PRINT : COLOR FG1,BG1:PRINT " ENTER DATA:";: COLOR FG,BG:PRINT TAB(21) "6- MANUAL" 'line 1400
500 PRINT TAB(21) "7- UREAD" 'line 1800
510 PRINT
520 COLOR FG1,BG1:PRINT " MODIFY DATA:";:COLOR FG,BG: PRINT TAB(21) "8- EDIT" 'line 2000
530 PRINT TAB(21) "9- SCALE" 'line 2200
540 PRINT TAB(20) "10- ZERO" 'line 2400
550 PRINT:COLOR FG1,BG1:PRINT " PARAMETERS:";:COLOR FG,BG: PRINT TAB(20) "11- ENTER/REVIEW/CHANGE" 'line 2500
570 PRINT " 12- FIX" 'line 2800
580 PRINT " 13- FREE" 'line 3000
590 PRINT
600 COLOR FG1,BG1:PRINT " DATA & PARAM: ";:COLOR FG,BG: PRINT "14- LIST " ' line 3200
610 PRINT " 15- SAVE ON DISK" 'line 3400
620 PRINT " 16- READ FROM DISK" 'line 3600
630 COLOR 15,BG: INPUT; "ENTER CHOICE";KMND:COLOR FG,BG:PRINT
650 ON KMND+1 GOTO 420,800,850,900,15000,1300,1400,1800,2000, 2200,2400,2500,2800,3000,3200,3400,3600
660 PRINT "*** ERROR *** ";KMND;" INVALID COMMAND": GOTO 400
800 'enter a title for documentation ---------------------------
810 INPUT "ENTER TITLE: ";TITL$:LOCATE 25,1:PRINT TITL$;SPC(11)
820 GOTO 420
850 'toggle printer on/off -------------------------------------
860 PFLG% = 1 - PFLG%: GOTO 420
900 'solve the mrqdt non-linear lst sq fit problem -------------
920 ITER% = 0 : IF IPFLG < > 0 THEN ITER% = NITER%
930 IPFLG = 0:ISVFL = 0 : CLS : GOSUB 10000
940 INPUT "HOW MANY ITERATIONS? ";MXITER%
950 IF MXITER% < 0 THEN MXITER% = 0
960 GOSUB 6000 ' go fit !
970 IPFLG = - 1 : NITER% = NITER% + ITER%
990 PRINT:PRINT: PRINT TITL$ :PRINT NITER%;" ITERATIONS": PRINT
1000 IF PFLG% = 1 THEN LPRINT:LPRINT TITL$ :LPRINT NITER%;" iterations "
1010 GOSUB 9000
1020 IF FLG%=1 THEN PRINT:PRINT "CHOLESKY NEGATIVE DIAGONAL--"; "UNABLE TO SOLVE WITH SUPPLIED INITIAL PARAMETERS"
1030 PRINT : PRINT "PRESS ANY KEY FOR FITTING STATISTICS"
1040 WHILE INKEY$ = "" : WEND
1050 GOSUB 1100 : PRINT : GOTO 400 'print statistics and return
1070 'print fit statistics -------------------------------------
1100 PRINT : PRINT "SOME FITTING STATISTICS:"
1110 PRINT "SIGMA= ";SIG;" R= ";R;: PRINT TAB( 41); "WGT'D SUM OF SQ. = ";WSS
1120 CHI2 = INT (10 * CHI2) / 10
1130 PRINT "CHI SQUARED= ";CHI2;" / ";NF;" DEG OF FREEDOM"
1140 PRINT "# OF CALLS TO SUM OF SQ=";NSSC;: PRINT TAB( 41);"# OF DERIV CALLS=";NDC: PRINT "# INC IN LAMBDA=";INCR;" LAMBDA= ";LAMBDA
1150 IF PFLG% <> 1 THEN RETURN
1160 LPRINT : LPRINT "SOME FITTING STATISTICS:"
1170 LPRINT "SIGMA= ";SIG;" R= ";R;: LPRINT TAB( 41);"WGT'D SUM OF SQ. = ";WSS
1180 LPRINT "CHI SQUARED= ";CHI2;" / ";NF;" DEG OF FREEDOM"
1190 LPRINT "# OF CALLS TO SUM OF SQ=";NSSC;: LPRINT TAB( 41);"# OF DERIV CALLS=";NDC: LPRINT "# INC IN LAMBDA=";INCR;" LAMBDA= ";LAMBDA
1200 RETURN
1300 'quit -----------------------------------------------------
1310 IF ISVFL < > 0 THEN 1360
1320 INPUT "PRESENT DATA NOT SAVED. SAVE IT?? (Y/N)";T1$
1330 IF LEFT$ (T1$,1) = "Y" THEN 3400 'go save
1340 IF LEFT$ (T1$,1) <> "N" THEN 420
1360 DEF SEG=64:POKE 23,(PEEK(23) AND 191):DEF SEG 'clear caps
1370 CLS: END
1400 'manual data entry ---------------------------------------
1410 PRINT "MANUAL DATA ENTRY - ": PRINT " (, TO EXIT)"
1412 ' set flags to indicate data points that currently exist
1415 FOR K=1 TO NOBS%:XP(K)=1:NEXT : FOR K = NOBS%+1 TO MXOBS%:XP(K)=0:NEXT
1420 PRINT "POINT X,MEASUREMENT"
1425 PRINT "===== ====,==========="
1430 FOR I = 1 TO MXOBS%
1440 PRINT I;: INPUT " ";T1$,T2$
1450 IF T1$ = "" THEN NOBS% = I - 1: GOTO 1480
1460 X(I) = VAL (T1$):DTA(I) = VAL (T2$) :XP(I) = 1
1470 NEXT
1480 INPUT "WEIGHTS-ENTER 'NO','STAT' OR 'EXPLICIT'?";T1$
1490 IF T1$ = "NO" THEN FOR I=1 TO NOBS%:WGT(I)=1:NEXT:GOTO 1580
1500 IF T1$ = "STAT" THEN FOR I = 1 TO NOBS%: WGT(I)=SQR (DTA(I)): NEXT : GOTO 1580
1510 IF T1$ < > "EXPLICIT" GOTO 1480
1520 PRINT : PRINT "POINT X Y WEIGHT": PRINT "===== ===== ===== ======"
1530 FOR I = 1 TO NOBS%
1540 PRINT I;" ";X(I);" ";DTA(I);" ";WGT(I);
1550 INPUT "New Weight=";WGT$:IF WGT$="" THEN 1570
1560 WGT(I) = VAL(WGT$)
1570 NEXT
1580 NOBS% = 0 : PRINT "NOW ORDERING & REVIEWING DATA"
1600 FOR I = 1 TO MXOBS%
1610 IF XP(I) = 0 GOTO 1650 'zero it if pt is to be deleted
1620 NOBS% = NOBS% + 1
1630 X(NOBS%) = X(I):DTA(NOBS%) = DTA(I):WGT(NOBS%) = WGT(I)
1640 IF I < > NOBS% THEN XP(I) = 0
1650 NEXT
1680 IPFLG = 0:ISVFL = 0 : GOTO 420
1800 'user defined read routine --------------------------------
1810 PRINT "NO USER DEFINED ROUTINE IMPLEMENTED"
1820 GOTO 400
2000 'edit data ------------------------------------------------
2005 FOR K=1 TO NOBS%:XP(K)=1:NEXT
2010 FOR K = NOBS%+1 TO MXOBS%:XP(K)=0:NEXT
2015 PRINT "ENTER 'W' TO CHANGE ONLY WEIGHTS,";: INPUT "'D' TO CHANGE DATA & WEIGHTS";T1$
2020 IF T1$ = "W" GOTO 1480
2030 PRINT "ENTER DATA PT RANGE FOR EDITING (N1,N2)"
2040 INPUT "(, TO EXIT)";T1$,T2$
2050 IF T1$ = "" GOTO 1580
2060 I = VAL (T1$):J = VAL (T2$)
2070 IF I<1 OR J>MXOBS% THEN PRINT "INVALID RANGE":GOTO 2030
2080 FOR K = I TO J
2090 PRINT "CURRENT VALUE OF X,DTA,WGT FOR PT #";K;" =": PRINT X(K);" ";DTA(K);" ";WGT(K)
2100 PRINT "ENTER NEW VALUE FOR X(";K;")"
2105 PRINT "(ENTER 'D' TO DELETE PT, OR 'enter' ";: INPUT "TO LEAVE UNCHANGED)";T1$
2110 IF T1$ = "D" THEN XP(K) = 0: GOTO 2150
2120 IF T1$ = "" THEN 2150
2130 X(K) = VAL (T1$) : XP(K) = 1
2140 INPUT "ENTER NEW VALUES FOR DTA,WGT ";DTA(K),WGT(K)
2150 NEXT
2160 GOTO 2030
2200 'scale x,dta,wgt --------------------------------------
2210 INPUT "ENTER X-COORDINATE SCALE FACTOR";XSCALE
2220 INPUT "ENTER DATA POINT SCALE FACTOR";DSCALE
2230 INPUT "ENTER WEIGHT SCALE FACTOR";WSCALE
2240 FOR I = 1 TO NOBS%
2250 X(I)=X(I)*XSCALE:DTA(I)=DTA(I)*DSCALE:WGT(I)=WGT(I)*WSCALE
2280 NEXT
2290 IPFLG = 0:ISVFL = 0 : GOTO 420
2400 'zero data & parameters -----------------------------------
2410 FOR I=1 TO MXOBS%:X(I)=0:DTA(I)=0:WGT(I)=0:NEXT:NOBS% = 0
2420 FOR I=1 TO MXVAR%:PARM(I)=0:DPARM(I) = 0: NEXT :NPRM% = 0
2430 IPFLG = 0:ISVFL = - 1 : GOTO 420
2500 'enter/review/change param --------------------------------
2510 CLS:GOSUB 9000 : IF NPRM% < 1 THEN 2580
2530 PRINT "CHANGE PARAMETERS? ENTER: 'A' TO CHANGE ALL": PRINT TAB(29)"'S' TO SELECTIVELY CHANGE (or add parameters)"
2540 PRINT TAB(29) "press RETURN to leave unchanged";:INPUT T1$
2550 IF T1$ = "" GOTO 420
2560 IF T1$ = "S" THEN 2700
2570 IF T1$ < > "A" THEN 2530
2580 PRINT "ENTER PARAMETERS ONE AT A TIME.": PRINT " (NULL TO EXIT)"
2590 FOR I = 1 TO MXVAR%
2600 PRINT I;"- "; : INPUT T$ : PRINT
2610 IF T$ = "" THEN NPRM% = I - 1: GOTO 2660
2620 IF LEFT$ (T$,1) = "." OR LEFT$ (T$,1) = "-" THEN 2640
2630 IF LEFT$ (T$,1) < "0" OR LEFT$ (T$,1) > "9" THEN PRINT T$ "INVALID, RETYPE": GOTO 2600
2640 PARM(I) = VAL (T$)
2650 NEXT
2660 IF NPRM% < = 0 GOTO 420
2670 FOR I = 1 TO NPRM%:DPARM(I) = 0: NEXT
2680 IPFLG = 0 : ISVFL = 0 : GOTO 420
2700 '----- change some of the param
2710 PRINT "ENTER PARM#, AND VALUE": PRINT SPC(10)"(, TO EXIT)"
2720 INPUT T1$,T2$: IF T1$ = "" THEN GOSUB 9000: GOTO 400
2730 IF VAL(T1$) = NPRM%+1 THEN NPRM%=NPRM%+1
2740 IF VAL (T1$) < 1 OR VAL (T1$) > NPRM% THEN PRINT "INVALID PARM#. RANGE IS 1-";NPRM%+1: GOTO 2720
2750 IF LEFT$ (T2$,1) = "." OR LEFT$ (T2$,1) = "-" THEN 2770
2760 IF LEFT$ (T2$,1) < "0" OR LEFT$ (T2$,1) > "9" THEN PRINT T2$ "INVALID, RETYPE": GOTO 2720
2770 PARM( VAL (T1$)) = VAL (T2$)
2780 GOTO 2720
2800 'fix some parameters -------------------------------------
2810 GOSUB 9000
2820 IF NPRM% < 1 THEN 400
2830 INPUT "ENTER PARM# TO BE FIXED (NULL TO EXIT)";I
2840 IF I = 0 GOTO 2870
2850 IF I<1 OR I>NPRM% THEN PRINT "INVALID PARM#. RANGE IS 1-" ;NPRM%: GOTO 2800
2860 KFIX(I) = 1 : F1% = 1 : GOTO 2830
2870 IF F1% = 0 GOTO 400 'NOTHING CHANGED
2880 GOSUB 9000 : IPFLG = 0:ISVFL = 0 : GOTO 400
3000 'free some previously fixed param.-------------------------
3010 GOSUB 9000 : IF NPRM% < 1 THEN 400
3030 INPUT "ENTER PARM# TO BE FREED (NULL TO EXIT)";I
3040 IF I = 0 GOTO 3070
3050 IF I < 1 OR I > NPRM% THEN PRINT "INVALID PARM#. RANGE IS 1-";NPRM%: GOTO 3000
3060 KFIX(I) = 0 : F1% = 1 : GOTO 3030
3070 IF F1% = 0 GOTO 400
3080 GOSUB 9000 : IPFLG = 0:ISVFL = 0 : GOTO 400
3200 'print data and param values ------------------------------
3210 CLS:GOSUB 10000:PRINT "MARQUARDT LEAST SQUARES - REV ";REV
3220 PRINT TITL$: PRINT NITER%;" ITERATIONS": PRINT
3230 IF PFLG%=1 THEN LPRINT TITL$:LPRINT NITER%;" ITERATIONS"
3240 GOSUB 9000 : GOSUB 1100 'print parameters and statistics
3260 PRINT:PRINT NOBS%;" DATA POINTS BEING FITTED": PRINT SPC(18)"(X,DTA,WGT,FMM)"
3270 IF PFLG%=1 THEN LPRINT:LPRINT NOBS%; " DATA POINTS BEING FITTED":LPRINT SPC(18) "(X,DTA,WGT,FMM)"
3280 IF NOBS% < = 0 GOTO 3360
3290 PFORM$ = "##.##^^^^ "
3300 FOR I = 1 TO NOBS%
3310 IF BRKFLG% THEN BRKFLG% = 0:PRINT "BREAK IN LISTING": GOTO 400
3320 GOSUB 20000:FMM = FUNCTN - DTA(I)
3330 PRINT USING PFORM$;X(I),DTA(I),WGT(I),FMM
3340 IF PFLG%=1 THEN LPRINT USING PFORM$;X(I),DTA(I),WGT(I),FMM
3350 NEXT
3360 GOTO 400
3400 'save data & parameters ---------------------------------
3410 PRINT "THESE ARE YOUR CURRENT FILES" : FILES DRV$ + "*.*"
3430 PRINT : INPUT "SAVE DATA AS DISK FILE NAMED ";T1$
3435 IF MID$(T1$,2,1) <> ":" THEN T1$ = DRV$ + T1$
3440 OPEN "O",2,T1$ : IF RETCOD <> 0 THEN CLOSE 2 : GOTO 400
3460 WRITE #2, TITL$ : WRITE #2, NOBS%
3470 FOR I = 1 TO NOBS%: WRITE #2, X(I),DTA(I),WGT(I): NEXT
3480 WRITE #2, NPRM%
3485 FOR I = 1 TO NPRM%:WRITE #2, PARM(I),DPARM(I),KFIX(I):NEXT
3490 CLOSE 2: IPFLG = 0:ISVFL = - 1 : GOTO 420
3600 'read data & param from disk -----------------------------
3610 PRINT "THESE ARE YOUR CURRENT FILES" : FILES DRV$ + "*.*"
3630 PRINT:INPUT "READ DATA & PARAM FROM DISK FILE NAMED ";T1$
3635 IF MID$(T1$,2,1) <> ":" THEN T1$ = DRV$ + T1$
3640 OPEN "I",3,T1$ : IF RETCOD <> 0 THEN CLOSE 3 : GOTO 400
3660 INPUT #3, TITL$ : INPUT #3, NOBS%
3670 FOR I = 1 TO NOBS%: INPUT #3, X(I),DTA(I),WGT(I): NEXT
3680 INPUT #3, NPRM%
3685 FOR I = 1 TO NPRM%:INPUT #3, PARM(I),DPARM(I),KFIX(I):NEXT
3690 CLOSE 3
3700 IPFLG = 0:ISVFL = - 1:GOSUB 9000:PRINT
3705 LOCATE 25,1:PRINT TITL$;:LOCATE 21 : PRINT : GOTO 400
4000 'subroutine to compute chi-squared ------------------------
4010 CHI2 = 0
4020 FOR I = 1 TO NOBS%
4030 IF WGT(I) = 0 THEN 4060
4040 GOSUB 20000
4050 CHI2 = CHI2 + ((FUNCTN - DTA(I)) / WGT(I)) ^ 2
4060 NEXT
4070 RETURN
4500 'subroutine obtains CHOLESKY backward solution of matrix A
4510 G(1) = G(1) / A(1)
4520 IF NFIT% < = 1 THEN 4630
4530 L = 1
4540 FOR I = 2 TO NFIT%
4550 K = I - 1
4560 FOR J = 1 TO K
4570 L = L + 1 : G(I) = G(I) - A(L) * G(J)
4590 NEXT
4600 L = L + 1 : G(I) = G(I) / A(L)
4620 NEXT
4630 MDI% = NFIT% * (NFIT% + 1) / 2
4640 G(NFIT%) = G(NFIT%) / A(MDI%)
4650 IF NFIT% < = 1 THEN RETURN
4660 FOR K1 = 2 TO NFIT%
4670 I = NFIT% + 2 - K1
4680 K = I - 1 : L = I * K / 2
4700 FOR J = 1 TO K
4710 G(J) = G(J) - G(I) * A(L + J)
4720 NEXT
4730 G(K) = G(K) / A(L)
4740 NEXT
4750 RETURN
5000 'subroutine to perform CHOLESKI decomposition of matrix a
5010 FLG% = 0
5020 FOR J = 1 TO NFIT%
5030 L = J * (J + 1) / 2
5040 IF J < = 1 THEN 5120
5050 FOR I = J TO NFIT%
5060 K1 = I * (I - 1) / 2 + J : F = A(K1) : K2 = J - 1
5090 FOR K = 1 TO K2:F = F - A(K1 - K) * A(L - K): NEXT
5100 A(K1) = F
5110 NEXT
5120 IF A(L) > 0 THEN 5160
5130 FLG% = 1 : PRINT "CHOLSKI-NEG DIAG J,L,A(L)= ";J,L,A(L)
5150 RETURN
5160 F = SQR (A(L))
5170 FOR I = J TO NFIT%
5180 K2 = I * (I - 1) / 2 + J : A(K2) = A(K2) / F
5200 NEXT
5210 NEXT
5220 RETURN
5500 'subroutine to calculate the weighted sum of squares ------
5510 WSS = 0 : NSSC = NSSC + 1
5520 FOR I = 1 TO NOBS%
5530 GOSUB 20000
5540 WSS = WSS + (WGT(I) * (FUNCTN - DTA(I))) ^ 2
5550 NEXT
5570 RETURN
5700 'subroutine to calculate the sum of squares ---------------
5710 SS = 0 : NSSC = NSSC + 1
5720 FOR I = 1 TO NOBS%
5730 GOSUB 20000 : SS = SS + (FUNCTN - DTA(I)) ^ 2
5750 NEXT
5770 RETURN
5900 'subroutine to calculate the sum of DTA(I)^2 --------------
5910 R = 0
5920 FOR I = 1 TO NOBS% : R = R + DTA(I) ^ 2 : NEXT
5950 RETURN
5990 'subroutine to do the main mathematics of the fitting -----
6000 NFIT% = 0:NX% = 0
6010 IF NPRM% < 1 THEN RETURN 2500
6020 FOR I = 1 TO NPRM%
6030 IF KFIX(I) = 0 GOTO 6070
6040 NX% = NX% + 1
6050 DPARM(NX%) = 0!
6060 GOTO 6090
6070 NFIT% = NFIT% + 1
6080 B(NFIT%) = PARM(I)
6090 NEXT
6100 IF NFIT% <= 0 THEN NITER% = ITER% : RETURN 420
6140 'perform MARQUARDT fitting --------------------------------
6150 IF NOBS% >= NFIT% THEN 6180
6160 PRINT "# OF DATA PTS (NOBS%= ";NOBS%;")";" IS LESS THAN"; TAB( 41);"# OF PARAM. TO BE FIT (NFIT%= ";NFIT%;")"
6165 PRINT "MODEL IS UNDETERMINED"; CHR$ (7)
6170 NITER% = ITER% : RETURN 400
6180 PRCSN = 2.5E-07 : LAMBDA = .01 : LMIN = 1E+20 : PHI = 1
6190 MDI% = NFIT% * (NFIT% + 1) / 2
6200 NSSC = 0 : NDC = 0 : NITER% = 0 : INCR = 0
6210 GOSUB 5500 ' Choleski decomposition
6220 PRINT "WGT'D SSQ = ";WSS
6225 IF PFLG%=1 THEN LPRINT "WGT'D SSQ = ";WSS
6230 GOTO 6280
6240 'NEXT ITERATION -------------------------------------------
6250 NITER% = NITER% + 1
6260 IF (NITER% > 4 AND LAMBDA < LMIN) THEN LMIN = LAMBDA
6270 LOCATE ,13: PRINT WSS : IF PFLG% = 1 THEN LPRINT WSS;" ";
6280 IF NITER% >= MXITER% THEN PRINT MXITER%;" ITERATIONS - PAUSE": GOTO 6920
6290 IF BRKFLG% THEN BRKFLG% = 0 : PRINT "OPERATOR INTERRUPT": GOTO 6920
6300 COLOR FG2,BG2 : PRINT "COMPUTING ";: COLOR FG1,BG1
6305 PRINT " ITERATION #";NITER% + 1;: COLOR FG,BG:PRINT
6310 '------- DECREASE LAMBDA
6320 LAMBDA = .31622777# * LAMBDA : INCR = 0
6340 '------- CALCULATE A=JTJ AND JTF
6350 FOR I = 1 TO MDI%:A(I) = 0: NEXT
6360 FOR I = 1 TO NFIT%:GRAD(I) = 0: NEXT
6370 FOR I = 1 TO NOBS%
6380 GOSUB 21000
6390 FMM = (F - DTA(I)) * WGT(I)
6400 J = 0
6410 FOR K = 1 TO NPRM%
6420 IF KFIX(K)=0 THEN J = J+1:DERIV(J) = DERIV(K)*WGT(I)
6430 NEXT
6440 FOR J = 1 TO NFIT%
6450 GRAD(J) = GRAD(J) + DERIV(J) * FMM
6460 L = J * (J - 1) / 2
6470 FOR K=1 TO J: A(L+K)=A(L+K)+DERIV(J)*DERIV(K): NEXT
6480 NEXT
6490 NEXT
6500 NDC = NDC + 1
6510 '------ SAVE "A" MATRIX AND CURRENT PARAMETER VALUES "B"
6520 FOR I = 1 TO MDI%:C(I) = A(I): NEXT
6530 FOR I = 1 TO NFIT%:DERIV(I) = B(I): NEXT
6540 '------ DOCTOR "A" MATRIX DIAGONAL ELEMENTS TO BE:
6550 ' A = A(1+LAMBDA) + PHI*LAMBDA
6560 DA = PHI * LAMBDA
6570 FOR J = 1 TO NFIT%
6580 G(J) = - GRAD(J)
6590 L = J * (J + 1) / 2
6600 A(L) = C(L) * (1 + LAMBDA) + DA
6610 K = J - 1
6620 IF K > 0 THEN FOR I = 1 TO K:A(L - I) = C(L - I): NEXT
6630 NEXT
6650 GOSUB 5000 'Cholesky decomposition
6660 IF FLG% <> 0 GOTO 6840
6680 GOSUB 4500 'calculate g (the change in parameters)
6690 '------ FIND NEW PARAMETERS B = D+G
6700 ' (N0 COUNTS THE # OF ZERO ELEMENTS IN G)
6710 N0 = 0 : I = 0
6720 FOR J = 1 TO NPRM%
6730 IF KFIX(J) < > 0 GOTO 6780
6740 I = I + 1
6750 B(I) = DERIV(I) + G(I)
6760 IF ABS (G(I)) <= ABS (PRCSN*DERIV(I)) THEN N0 = N0 + 1
6770 PARM(J) = B(I)
6780 NEXT
6790 IF N0 = NFIT% GOTO 6890
6800 OLDWSS = WSS : GOSUB 5500 'update the wss
6820 IF WSS < OLDWSS GOTO 6250 'next iteration
6830 '------ last step too big; increase lambda
6840 IF LAMBDA < PRCSN THEN LAMBDA = PRCSN
6850 INCR = INCR + 1
6860 LAMBDA = 10! * LAMBDA
6870 IF LAMBDA < = 100000! * LMIN GOTO 6560
6880 '------ convergence reached
6890 RI = LAMBDA / LMIN
6900 CLS : GOSUB 10000 : PRINT " CONVERGENCE REACHED "
6905 PRINT "# OF PARAMS FIT = ";NFIT%
6907 PRINT "# OF PARAMS CONVERGED = ";N0
6910 PRINT "LAMBDA/L(MIN) = ";RI
6920 NF = NOBS% - NFIT%
6930 IF NF < = 0 GOTO 6990
6940 GOSUB 5700 'calc sum of squares
6950 SIG = SQR (SS / NF)
6960 GOSUB 5900 'calc sum of dta^2
6970 R = SQR (SS / R) * 100!
6980 GOSUB 4000 'compute chi-squared
6990 IF NITER% <= 0 GOTO 7130
7000 FOR J = 1 TO MDI%:A(J) = C(J): NEXT : GOSUB 5000
7010 IF FLG% = 0 GOTO 7060
7020 FOR J = 1 TO NPRM%
7030 IF KFIX(J) = 0 THEN PARM(J) = 999.0001
7040 NEXT
7050 GOTO 7130
7060 K = 0
7070 FOR I4 = 1 TO NPRM%
7080 IF KFIX(I4) <> 0 GOTO 7120
7090 K = K + 1
7100 FOR J = 1 TO NFIT%:G(J) = 0!: NEXT :G(K) = 1!
7110 GOSUB 4500:DPARM(I4) = SQR ( ABS (G(K))) * SIG
7120 NEXT
7130 RETURN
9000 'list the current values of the parameters ----------------
9010 IF NPRM% < 1 THEN PRINT "NO PARAM ENTERED": RETURN
9020 PRINT
9025 PRINT NPRM%; " FITTING PARAMETERS & THEIR ERRORS" : PRINT
9030 IF PFLG%= 1 THEN LPRINT : LPRINT NPRM%; " FITTING PARAMETERS AND THEIR ERRORS":LPRINT
9040 FOR I = 1 TO NPRM%
9050 IF PFLG% = 0 GOTO 9080
9060 LPRINT I;") ";PARM(I);
9070 IF KFIX(I) = 0 THEN LPRINT " +- ";DPARM(I) ELSE LPRINT " (FIXED) "
9080 PRINT I;") ";PARM(I);
9090 IF KFIX(I) = 0 THEN PRINT " +- "; DPARM(I) ELSE PRINT " (FIXED) "
9100 NEXT
9110 PRINT : RETURN
9999 ' ----------- FUNCTION KEY and HELP SUBROUTINES -----------
10000 'display "help" / title line -----------------------------
10005 XCURSOR = CSRLIN : YCURSOR = POS(0) : LOCATE 25,1
10010 IF SHOWTITLE THEN COLOR FG2,BG:PRINT TITL$; ELSE COLOR FG2,BG : PRINT " 1- SHOW FUNCTION KEYS"; " 2- SHOW TITLE 3- BREAK 4- QUICK-PLOT";:COLOR FG,BG
10020 LOCATE XCURSOR,YCURSOR : RETURN
10200 SHOWTITLE=0: GOSUB 10000: RETURN 'display "HELP" line---F1
10300 SHOWTITLE = -1: GOSUB 10000: RETURN 'display title -----F2
10310 BRKFLG% = 1 : RETURN 'user interrupt (break function) -F3
10400 CLS : PRINT TAB(15); "QUICK PLOT" ' --------------------F4
10410 PRINT TAB(10); " Y "; YSTYL$; " VS."; " X ";XSTYL$;" PLOT"
10420 IF PLOTSET% = 0 THEN PRINT "PLOT NOT DEFINED - FIRST USE MENU OPTION #4" : PRINT"PRESS ANY KEY TO CONTINUE":WHILE INKEY$="":WEND: RETURN
10430 GOSUB 16000 'scale data log or linear
10440 GOSUB 16300 'calculate fitting function
10450 IF XNEG THEN PRINT "WARNING: NEGATIVE X VALUE. X LOG PLOT INVALID": XNEG=0:GOTO 10470
10460 GOSUB 16500 ' PLOT
10470 SCREEN 0 : RETURN
15000 'Plot data points and fitting function -------------------
15010 'Plot data points and fitting function -------------------
15020 CLS
15030 IF NPRM% < 1 AND NOBS% < 1 THEN PRINT TAB(20), "NO DATA POINTS OR PARAMETERS ENTERED":GOTO 400
15040 FOR I = 1 TO NPRM%
15050 IF PARM(I) < > 0 THEN GOTO 15080
15060 NEXT
15070 PRINT " WARNING: all parameters are currently = 0"
15080 RESPLOT = 0 'FLAG to indicate plot for residuals
15090 IF NOBS% < 1 THEN GOTO 15170
15100 PRINT TAB(15),"CHOOSE PLOT:":PRINT
15110 PRINT " 1- PLOT DATA AND FITTING FUNCTION"
15120 PRINT " 2- PLOT RESIDUALS [ABS(FIT MINUS MEASUREMENT)]"
15130 PRINT " 3- PLOT RESIDUALS [% FIT MINUS MEASUREMENT]"
15140 INPUT "ENTER CHOICE:";KMND
15150 IF KMND = 2 THEN RESPLOT = 1 : PCNT% = 0
15160 IF KMND = 3 THEN RESPLOT = 1 : PCNT% = 1
15170 PRINT TAB(15),"CHOOSE GRAPH STYLE:"
15180 PRINT "1- Y LINEAR VS. X LINEAR"
15185 PRINT "2- Y LINEAR VS. X LOG"
15190 IF RESPLOT = 1 GOTO 15210
15200 PRINT "3- Y LOG VS. X LINEAR":PRINT "4- Y LOG VS. X LOG"
15210 OLDSTYL%=GSTYL%:PRINT:INPUT "ENTER CHOICE:";GSTYL%
15220 IF GSTYL% = 0 THEN 400
15230 IF GSTYL% <> OLDSTYL% THEN PLOTSET% = 0
15240 XSTYL$="LINEAR"
15245 IF (GSTYL%=2 OR GSTYL%=4) THEN XSTYL$="LOG"
15250 YSTYL$="LINEAR"
15255 IF (GSTYL%=3 OR GSTYL%=4) THEN YSTYL$="LOG"
15260 CLS:PRINT TAB(15);" Y ";YSTYL$;" VS.";" X ";XSTYL$;" PLOT"
15270 IF NOBS% <1 THEN 15460
15280 ' GO SCALE THE DATA INTO PLOTTING ARRAY
15290 GOSUB 16000 'scale determine minimum and maximum of DTA
15300 IF XNEG THEN PRINT "WARNING: NEGATIVE X VALUE. X LOG PLOT INVALID": XNEG=0:GOTO 15170
15320 PRINT : PRINT "DATA POINTS: "
15330 PRINT "X VALUES range from: ";XP(1);" to ";XP(NOBS%)
15340 PRINT "Y VALUES range from: ";MINDTA;" to ";MAXDTA
15350 IF PLOTSET% = 0 THEN 15420
15360 PRINT "Current graph boundaries are:"
15370 PRINT " xmin = ";XMIN;" xmax = ";XMAX
15380 PRINT " ymin = ";YMIN;" ymax = ";YMAX
15390 PRINT:PRINT " Do you wish to change any of the graph boundaries (Y/N)"
15400 INPUT "(null to leave unchanged)";T1$
15410 IF T1$ = "" OR T1$ = "N" THEN 15460
15420 PRINT:INPUT "ENTER GRAPH XMIN,XMAX,YMIN,YMAX "; XMIN,XMAX,YMIN,YMAX
15425 IF XMIN = 0 AND XMAX = 0 GOTO 420
15430 PRINT:PRINT "ENTER xinterval,yinterval"; "(THE # OF INTERVALS ON THE x,y AXIS)";
15435 INPUT XINTERVAL, YINTERVAL
15440 PLOTSET% = 1
15450 IF RESPLOT = 1 OR NPRM%=0 THEN XINC = 2*(XMAX-XMIN)/MXOBS%:GOTO 15720
15460 PRINT:PRINT "PLOT OF FITTED FUNCTION"; "(FROM CURRENT VALUE OF PARAMETERS):"
15470 IF NOBS% < 1 AND PLOTSET% = 0 GOTO 15530
15480 PRINT "The function will be plotted in the range "; XMIN; " to ";XMAX
15490 INPUT "ENTER X INCREMENT for plotting the function";XINC
15500 IF XINC <=0 THEN PRINT "INVALID ENTRY":GOTO 15480
15510 IF (XMAX-XMIN)/XINC > MXOBS% THEN PRINT "too many points, must be fewer than ";MXOBS%: GOTO 15480
15520 GOTO 15570
15530 PRINT " NO DATA CURRENTLY ENTERED"
15540 PRINT:PRINT "ENTER XMIN,XMAX AND X-INCREMENT"
15550 INPUT "for evaluating fitting function";XMIN,XMAX,XINC
15560 IF (XMAX-XMIN)/XINC > MXOBS% THEN PRINT "too many points, must be fewer than ";MXOBS%: GOTO 15530
15570 GOSUB 16300 ' evaluate function
15580 PRINT:PRINT "MINIMUM of fitted function= ";MINYP
15590 PRINT "MAXIMUM of fitted function= ";MAXYP
15600 PRINT:PRINT "current graph boundaries are:"
15610 PRINT " xmin = ";XMIN;" xmax = ";XMAX
15620 PRINT " ymin = ";YMIN;" ymax = ";YMAX
15630 IF NOBS%<1 THEN 15670
15640 PRINT
15645 PRINT "do you wish to change THESE GRAPH BOUNDARIES?(Y/N)"
15650 INPUT "(null to leave unchanged)";T1$
15660 IF T1$ = "" OR T1$ = "N" THEN 15720
15670 PRINT:PRINT "ENTER NEW YAXIS BOUNDARY VALUES -- YMIN,YMAX"
15680 INPUT "(ENTER , TO CHANGE ALL GRAPH BOUNDARIES)";T1$,T2$
15690 IF T1$ = "" THEN 15420
15700 YMIN = VAL(T1$):YMAX = VAL(T2$)
15710 PRINT: PRINT "ENTER xinterval,yinterval"; " (THE # OF INTERVALS ON THE x,y AXIS)"
15715 INPUT XINTERVAL, YINTERVAL
15720 GOSUB 16500 'go and plot
15730 SCREEN 0 : GOTO 420 'finished plotting
16000 'Scale data & find the minima and maxima of data in YP(I)
16010 XNEG = 0
16020 MINDTA = 9.999999E+37: MAXDTA = -9.999999E+37
16030 FOR I = 1 TO NOBS%
16040 XP(I) = X(I): YP(I) = DTA(I)
16050 IF RESPLOT <> 1 THEN 16090
16060 NORM = DTA(I):IF NORM = 0 THEN NORM = 1E-10
16070 GOSUB 20000: YP(I) = FUNCTN - DTA(I) 'yes - calc residuals
16080 IF PCNT% <>0 THEN YP(I) = YP(I)/NORM ' plot % residual?
16090 IF (GSTYL%=1 OR GSTYL%=3) GOTO 16110 ' xlog plot?
16100 IF X(I)>0 THEN XP(I) = FNLGT(XP(I)) ELSE XNEG = 1 : RETURN
16110 IF (GSTYL%=1 OR GSTYL%=2) GOTO 16130 ' ylog plot?
16120 IF DTA(I)>0 THEN YP(I)=FNLGT(YP(I)) ELSE YP(I) = YMIN
16130 IF YP(I) >= MAXDTA THEN MAXDTA = YP(I)
16140 IF YP(I) <= MINDTA THEN MINDTA = YP(I)
16150 NEXT
16160 RETURN
16290 'calculate function using current parm values -----------
16300 PRINT:PRINT "CALCULATING FUNCTION...."
16305 IF NPRM% < 1 THEN RETURN
16310 I=0: KK=0: MINYP = 9.9E+37: MAXYP = -9.9E+37
16320 FOR XPT=XMIN TO XMAX STEP XINC
16330 KK=KK+1: FXP(KK) = XPT
16340 X(I) = XPT :IF (GSTYL%=1 OR GSTYL%=3) GOTO 16360
16350 X(I)=10^XPT ' FOR X-LOG PLOT
16360 GOSUB 20000
16370 FYP(KK) = FUNCTN 'FOR NON-LOG Y PLOT
16380 IF (GSTYL%=1 OR GSTYL%=2) GOTO 16400
16390 IF FUNCTN > 0 THEN FYP(KK)=FNLGT(FUNCTN) ELSE FYP(KK) = YMIN
16400 IF FYP(KK) >= MAXYP THEN MAXYP = FYP(KK)
16410 IF FYP(KK) <= MINYP THEN MINYP = FYP(KK)
16420 NEXT XPT
16430 KMAX = KK
16440 RETURN
16500 'plotting subroutine -- first axes and tick marks --------
16510 DELTAX = XMAX-XMIN: DELTAY = YMAX-YMIN: LETWID=8: LETHGT=8
16515 'hi-res screen & choose color 2 -for pc & 100% compatibles
16520 SCREEN 2:DEF SEG = &H0: OUT &H3D9,2
16530 LINE (XMIN.PIX,YMIN.PIX) - (XMAX.PIX,YMAX.PIX),,B
16540 IF XINTERVAL < 1 THEN XINTERVAL = 5
16550 ' X TICKS
16560 MINCOL = 0
16570 FOR TICK = 0 TO XINTERVAL
16580 TICKPLACE = XMIN.PIX + CINT(DELTAX.PIX*TICK/XINTERVAL)
16590 LINE(TICKPLACE,YMIN.PIX-2) - (TICKPLACE,YMIN.PIX+2)
16600 LINE(TICKPLACE,YMAX.PIX-2) - (TICKPLACE,YMAX.PIX+2)
16610 TICCOL = INT(TICKPLACE/LETWID)-1
16620 VAL.LAB = XMIN + (TICK/XINTERVAL)*DELTAX
16630 IF (GSTYL%=2 OR GSTYL%=4) THEN VAL.LAB = 10^VAL.LAB
16640 TICLAB = VAL.LAB:GOSUB 18000
16650 TICCOL = TICCOL - LEN(FORMAT$)/2 + 2
16660 IF TICCOL + LEN(FORMAT$) > 80 THEN 16700
16670 IF TICCOL < MINCOL GOTO 16700
16680 LOCATE 25,TICCOL: MINCOL = TICCOL + LEN(FORMAT$)
16690 PRINT USING FORMAT$;TICLAB;
16700 NEXT TICK
16710 IF YINTERVAL < 1 THEN YINTERVAL = 5
16720 ' Y TICKS
16730 OLDROW = 26
16740 FOR TICK = 0 TO YINTERVAL
16750 TICKPLACE = YMIN.PIX - CINT(DELTAY.PIX*TICK/YINTERVAL)
16760 LINE(XMIN.PIX-2,TICKPLACE) - (XMIN.PIX+2,TICKPLACE)
16770 LINE(XMAX.PIX-2,TICKPLACE) - (XMAX.PIX+2,TICKPLACE)
16780 TICROW = INT (TICKPLACE/LETHGT) + 1
16790 IF TICROW >= OLDROW-1 THEN GOTO 16860
16800 VAL.LAB = YMIN + (TICK/YINTERVAL) * DELTAY
16810 IF (GSTYL%=3 OR GSTYL%=4) THEN VAL.LAB = 10^VAL.LAB
16820 TICLAB = VAL.LAB :GOSUB 18000
16830 TICCOL = 8 - LEN(FORMAT$):IF TICCOL < 1 THEN TICCOL=1
16840 LOCATE TICROW,TICCOL : OLDROW = TICROW
16850 PRINT USING FORMAT$;TICLAB;
16860 NEXT TICK
17000 'plot points and function --------------------------------
17010 FOR I = 1 TO NOBS%
17020 CIRCLE (FNSX(XP(I)),FNSY(YP(I))),4
17030 NEXT
17040 IF RESPLOT = 1 OR NPRM% < 1 GOTO 17120 ' no function plot
17050 IWENT%=0
17060 FOR K = 1 TO KMAX
17070 XPT = FNSX(FXP(K)): YPT = FNSY(FYP(K))
17080 IF XPT<0 OR XPT>XTOTAL.PIX OR YPT<0 OR YPT>YTOTAL.PIX THEN 17110 ' pt out of range
17090 IF IWENT% = 0 THEN PSET (XPT,YPT) : IWENT%= 1
17100 LINE -(XPT,YPT)
17110 NEXT K
17120 GTITL$ = TITL$: PCNT$ = "": IF PCNT% = 1 THEN PCNT$="(%)"
17130 IF RESPLOT = 1 THEN GTITL$ = GTITL$+" - RESIDUALS"+PCNT$
17140 LOCATE 1,50-LEN(GTITL$):PRINT GTITL$;
17150 WHILE INKEY$ = "" : WEND : RETURN
18000 'subroutine to format a label for axis -------------------
18020 FORMAT$="#"
18030 IF TICLAB=0 THEN RETURN
18040 ORDER=INT(LOG(ABS(TICLAB))/2.30258)
18050 IF ABS(ORDER)>=4 THEN FORMAT$ = "##.#^^^^" : RETURN
18060 IF ORDER<0 THEN FORMAT$=FORMAT$+".": GOTO 18080
18070 FORMAT$=FORMAT$+STRING$(ORDER+1,"#")+"."
18080 T=TICLAB
18090 TOL=ABS(TICLAB/100000!)
18100 FP=ABS(T-FIX(T)): IF 1-FP<FP THEN FP=1-FP
18110 WHILE FP>TOL
18120 T=T*10: TOL=TOL*10
18130 FP=ABS(T-FIX(T)): IF 1-FP<FP THEN FP=1-FP
18140 FORMAT$=FORMAT$+"#"
18150 WEND
18160 RETURN
19000 'error trap ----------------------------------------------
19010 IF RETCOD = 0 THEN RETCOD = -1 :ERRCNT = 1: GOTO 19030
19020 ERRCNT = ERRCNT + 1 ' error flagged again in same routine
19030 IF ERR=5 THEN PRINT "ILLEGAL FUNCTION CALL"
19040 IF ERR=6 THEN PRINT "OVERFLOW ERROR"
19050 IF ERR=53 OR ERR=54 THEN PRINT "FILE NOT FOUND"
19060 IF ERR=61 THEN PRINT "DISK FULL ERROR"
19070 IF ERR=70 OR ERR=71 THEN PRINT "DISK NOT READY OR WRITE PROTECTED"
19080 PRINT "ERROR #";ERR;" ON LINE NUMBER ";ERL
19090 IF ERRCNT > 5 THEN PRINT:PRINT "ROUTINE TERMINATING DUE TO ERROR COUNT ": GOTO 400
19100 PRINT "PRESS ANY KEY TO CONTINUE...":WHILE INKEY$="":WEND
19110 RESUME NEXT
20000 'subroutine to evaluate the function chosen to be fit
20005 'The function code here is for the video game problem
20010 FUNCTN = PARM(1) * (1 - EXP(-PARM(2) * X(I)))
20020 RETURN
20050 '
21000 'subroutine to evaluate the derivative of the function
21005 'with respect to each parameter. Only 2 parameters here.
21010 GOSUB 20000
21020 F = FUNCTN
21030 DERIV(1) = F / PARM(1)
21040 DERIV(2) = X(I) * (PARM(1)-F)
21050 RETURN